home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Developer / BBFig / Source / YapOutput.m < prev    next >
Text File  |  1992-05-13  |  9KB  |  334 lines

  1. /*
  2.  *  YapOutput.m
  3.  *  Author: Ali Ozer
  4.  *  Created: Mar 6, 1989
  5.  *  Modified: Jun & Jul 1989 for 1.0. Added NX_HANDLER for error detection.
  6.  *  Modified: Aug 90 for 2.0. Added use of second context for robustness.
  7.  *  Modified: Jan 92 for BBFig by Izumi Ohzawa (izumi@pinoko.berkeley.edu)
  8.  *
  9.  *  This class is a subclass of view that manages the output in Yap. It
  10.  *  provides a method (executeCodeFrom:) to execute PS from a text object.
  11.  *  The PostScript output will be displayed in the view. The output is
  12.  *  also cached in a bitmap for fast redraw response.
  13.  *
  14.  *  You may freely copy, distribute and reuse the code in this example.
  15.  *  NeXT disclaims any warranty of any kind, expressed or implied,
  16.  *  as to its fitness for any particular use.
  17.  */
  18.  
  19. #import "YapOutput.h"
  20. #import "YapApp.h"
  21. #import "YapWrap.h"    // Generated from YapWrap.psw
  22. #import "BBox.h"    // Generated from BBox.psw
  23.  
  24. #import <appkit/nextstd.h>
  25. #import <appkit/Panel.h>
  26. #import <appkit/Text.h>
  27. #import <appkit/Window.h>
  28. #import <dpsclient/wraps.h>
  29. #import <objc/error.h>
  30. #import <streams/streams.h>
  31. #import <libc.h>
  32. #import <string.h>
  33. #import <defaults.h>
  34. #import <sys/file.h>
  35. #import <stdio.h>
  36.  
  37. @implementation YapOutput
  38.  
  39.  
  40. /*
  41.  * initFrame: initializes the instance and creates a cache.
  42.  */
  43. - initFrame:(const NXRect *)viewFrame
  44. {
  45.     [super initFrame:viewFrame];
  46.     [self setCacheCleared:YES];
  47.     [self setCacheShown:NO];
  48.     [self setMeshON:YES];
  49.     [self setFigureBB:YES];
  50.     cache = [[Window allocFromZone:[self zone]]
  51.         initContent:&bounds 
  52.         style:NX_PLAINSTYLE
  53.         backing:NX_RETAINED
  54.         buttonMask:0
  55.         defer:NO];
  56.  
  57.     return self;
  58. }
  59.  
  60. /*
  61.  * Set/get parameters that determine behaviour.
  62.  */
  63. - (BOOL)isCacheCleared
  64. {
  65.     return clearCache;
  66. }
  67.  
  68. - (BOOL)isCacheShown
  69. {
  70.     return showCache;
  71. }
  72.  
  73. - (BOOL)isMeshON
  74. {
  75.     return meshON;
  76. }
  77.  
  78. - (BOOL)isFigureBB
  79. {
  80.     return figureBB;
  81. }
  82.  
  83. - setCacheCleared:(BOOL)flag
  84. {
  85.     clearCache = flag;
  86.     return self;
  87. }
  88.  
  89. - setCacheShown:(BOOL)flag
  90. {
  91.     showCache = flag;
  92.     return self;
  93. }
  94.  
  95. - setMeshON:(BOOL)flag
  96. {
  97.     meshON = flag;
  98.     return self;
  99. }
  100.  
  101. - setFigureBB:(BOOL)flag
  102. {
  103.     figureBB = flag;
  104.     return self;
  105. }
  106.  
  107.  
  108. /*
  109.  * sizeTo:: is called whenever the view is resized. It resizes the bitmap cache
  110.  * along with the view. It doesn't do anything if the new size is equal to the
  111.  * old one.
  112.  */
  113. - sizeTo:(NXCoord)width :(NXCoord)height
  114. {
  115.     if (width == frame.size.width && height == frame.size.height) return self;
  116.  
  117.     [super sizeTo:width :height];
  118.     [cache sizeWindow:width :height];
  119.     
  120.     return self;
  121. }
  122.  
  123. /*
  124.  * drawSelf: simply shows the cache.
  125.  */
  126. - drawSelf:(NXRect *)rects :(int)rectCount
  127. {
  128.     if (rectCount == 3) {  /* Scrolling diagonally; use last two rectangles */
  129.     rects++;
  130.     PScomposite (NX_X(rects), NX_Y(rects), NX_WIDTH(rects), NX_HEIGHT(rects), 
  131.             [cache gState], NX_X(rects), NX_Y(rects), NX_COPY);
  132.     rects++;
  133.     PScomposite (NX_X(rects), NX_Y(rects), NX_WIDTH(rects), NX_HEIGHT(rects), 
  134.             [cache gState], NX_X(rects), NX_Y(rects), NX_COPY);
  135.     } else {
  136.     PScomposite (NX_X(rects), NX_Y(rects), NX_WIDTH(rects), NX_HEIGHT(rects), 
  137.             [cache gState], NX_X(rects), NX_Y(rects), NX_COPY);
  138.     }
  139.  
  140.     return self;
  141. }
  142.  
  143. - free
  144. {
  145.     [cache free];
  146.     return [super free];
  147. }
  148.  
  149. /*
  150.  * Ugly function to write PostScript error.
  151.  */
  152. void WritePostScriptError (char *errStr, int errStrLength, NXHandler *errorState)
  153. {
  154.     char *streamAddr;
  155.     int streamLength, maxLength;
  156.     NXStream *errorStream;
  157.  
  158.     if ((errorState->code == dps_err_ps) && 
  159.     (errorStream = NXOpenMemory (NULL, 0, NX_WRITEONLY))) {
  160.         DPSPrintErrorToStream (errorStream, (DPSBinObjSeq)(errorState->data2));
  161.     NXFlush (errorStream);
  162.     NXGetMemoryBuffer (errorStream, &streamAddr, &streamLength, &maxLength);
  163.     if (streamLength > errStrLength-1) streamLength = errStrLength-1;
  164.     strncpy (errStr, streamAddr, streamLength);
  165.     errStr[streamLength] = 0;
  166.     NXCloseMemory (errorStream, NX_FREEBUFFER);
  167.     } else {
  168.     sprintf (errStr, "A non-PostScript error while running program.");
  169.     }
  170. }
  171.  
  172. /*
  173.  * SwitchContextsWithFocus() will make the specified context the current
  174.  * context and make it focus on the same area the old context was 
  175.  * focused on.
  176.  */
  177. static void SwitchContextsWithFocus (DPSContext newContext)
  178. {
  179.     float c1x, c1y, c2x, c2y;
  180.     float winCTM[6];
  181.     int realWinNum;
  182.     
  183.     GetFocus (&c1x, &c1y, &c2x, &c2y, winCTM, &realWinNum);
  184.     DPSSetContext (newContext);
  185.     ReFocus (realWinNum, winCTM, c1x, c1y, c2x, c2y);
  186. }
  187.  
  188. #define STATUSLENGTH 200    // Some large number for error string length
  189.  
  190. /*
  191.  * executeCodeFrom: treats the contents of the specified text object as
  192.  * a PostScript program and executes it. The code is copied from the
  193.  * text object into a memory stream and then sent to the server using
  194.  * DPSWriteData(). 
  195.  *
  196.  * For protection against errors, the PostScript code is interpreted in a
  197.  * context separate from the Application's own context (which is created
  198.  * in the +new method of Application).  We first focus on the cache,
  199.  * note the various parameters (global window number, the transformation
  200.  * matrix, and the clip path), and then switch to the alternate context and
  201.  * reapply the parameters to establish a focus on the same area.
  202.  *
  203.  * Protection against PostScript errors is provided through the use of
  204.  * NX_DURING/NX_HANDLER.   If an error occurs, we immediately blast the
  205.  * second context and report the first error encountered.  If no errors
  206.  * occur during the execution, then we hang on to the context as it can
  207.  * be reused.
  208.  *
  209.  * Note that the NXEPSImageRep class provides a similar (but more powerful)
  210.  * sort of functionality for EPS files.  Use that class rather than the code
  211.  * here if you wish to make use of EPS files in your application.  This code
  212.  * here is meant for unstructured, short pieces of PostScript code, 
  213.  * eactly the kind that Yap encounters...
  214.  */
  215. - executeCodeFrom:textObj andReturnBB: (float *)llx : (float *)lly
  216.                      : (float *)urx : (float *)ury
  217.                      usertime: (int *) utime
  218. {
  219. //    int utime;        /* Time taken to execute the code */
  220.     char status[STATUSLENGTH];    /* Array for error messages */
  221.     NXStream *psStream;        /* Memory stream for the PostScript */
  222.     char *psBuffer;        /* The buffer used by the stream */
  223.     int psLen;            /* And the length of this buffer */
  224.     static DPSContext yapContext = NULL;    /* The second context */
  225.     DPSContext curContext = DPSGetCurrentContext();
  226.     NXHandler exception;
  227.  
  228.     /* Order front output window */
  229.     [[self window] orderFront:self];
  230.  
  231.     /* Open a memory stream and write the text into it... */ 
  232.  
  233.     if (psStream = NXOpenMemory (NULL, 0, NX_WRITEONLY)) {
  234.     int dummy;
  235.         NXPrintf (psStream, "/yaptime usertime def "
  236.                       "/-showpage {} def\n");
  237.         [textObj writeText:psStream];
  238.         NXPrintf (psStream, "\n/yaptime usertime yaptime sub def\n");
  239.         NXFlush (psStream);
  240.     NXGetMemoryBuffer (psStream, &psBuffer, &psLen, &dummy);
  241.     } else {
  242.     [[self window] setTitle:"Can't open memory stream!"];
  243.     return self;
  244.     }
  245.  
  246.     [[self window] setTitle:"BUSY"];
  247.  
  248.     /* Lock focus on the cache. If user wishes to see the cache, bring it up. */
  249.  
  250.     [[cache contentView] lockFocus];
  251.     if (clearCache) NXEraseRect (&bounds);
  252.     if (showCache) [[cache center] orderFront:self];  
  253.  
  254.     /* Create the second context if it needs to be created. */
  255.  
  256.     if (yapContext == NULL) {
  257.     const char *app = [NXApp appName];
  258.     yapContext = DPSCreateContext(NXGetDefaultValue(app, "NXHost"),
  259.                       NXGetDefaultValue(app, "NXPSName"),
  260.                       NULL, NULL);
  261.     DPSSetContext (curContext);
  262.     }
  263.  
  264.     /* Focus the second context to whatever the first context is focused on. */
  265.  
  266.     SwitchContextsWithFocus (yapContext);
  267.  
  268.     /* This will let us know if there were any errors. */
  269.  
  270.     exception.code = 0;
  271.  
  272.     NX_DURING {
  273.     DPSPrintf(yapContext, "/yapwidth %f def /yapheight %f def\n",
  274.                             bounds.size.width, bounds.size.height);
  275.     if(meshON)
  276.        ShowMesh();        /* draws point grid */
  277.     if(figureBB)
  278.        SendBBfig();    /* pswrap func containing bbfig */
  279.     DPSWriteData(yapContext, psBuffer, psLen);
  280.     NXPing();  /* This does not return until the execution is done. */
  281.             /* If there were any errors, we jump to the handler. */
  282.     GetUserTime (utime);        /* utime already pointer */
  283.     sprintf (status, "BBFig Postscript Output (Execution Time %d ms)", *utime);
  284.  
  285.     if(figureBB)
  286.        GetBBox(llx, lly, urx, ury);    /* get BoundingBox; args are pointers */
  287.     else
  288.     {
  289.        *llx = *lly = 0.0;
  290.        *urx = *ury = 999.0;
  291.        *utime = -1;
  292.     }
  293.  
  294. /*
  295.     sprintf (status, "%%%%BoundingBox: %5.0f %5.0f %5.0f %5.0f",
  296.             *llx, *lly, *urx, *ury);
  297. */
  298.  
  299.     } NX_HANDLER {
  300.     exception = NXLocalHandler;    /* Make note of the error... */
  301.     } NX_ENDHANDLER
  302.  
  303.     /* Switch back to the app context. */
  304.  
  305.     DPSSetContext(curContext);
  306.  
  307.     /* In case of error, report it and blow the second context away. */
  308.     /* -> Destroy the second context anyway */
  309.     DPSDestroyContext(yapContext);
  310.     yapContext = NULL;
  311.  
  312.     if (exception.code != 0) {
  313. //    DPSDestroyContext(yapContext);
  314. //    yapContext = NULL;
  315.     WritePostScriptError (status, STATUSLENGTH, &exception);
  316.     *llx = *lly = 0.0;
  317.     *urx = *ury = 999.0;
  318.     *utime = -1;    /* error indication */
  319.     }
  320.  
  321.     if (showCache) [cache orderOut:self];
  322.     [[cache contentView] unlockFocus];
  323.     [self display];
  324.     [[self window] setTitle:status];
  325.  
  326.     NXCloseMemory (psStream, NX_FREEBUFFER);
  327.     
  328.     return self;
  329. }
  330.  
  331. @end
  332.  
  333.  
  334.